package com.market.web.model;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javax.faces.model.SelectItem;

import org.primefaces.event.map.OverlaySelectEvent;
import org.primefaces.model.map.DefaultMapModel;
import org.primefaces.model.map.LatLng;
import org.primefaces.model.map.MapModel;
import org.primefaces.model.map.Marker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.market.domain.Location;
import com.market.domain.PickupSchedule;
import com.market.domain.transients.DAY_OF_WEEK;

@Component("locationModel")
@Scope("session")
public class LocationModel extends GenericModel<Location> {

	@Autowired
	private UserModel userModel;

	private String currentDistrict;

	private List<PickupSchedule> allPickupSchedules;

	private DefaultMapModel map = new DefaultMapModel();

	public List<PickupSchedule> getAllPickupSchedules() {
		return allPickupSchedules;
	}

	public String getCurrentDistrict() {
		return currentDistrict;
	}

	public List<SelectItem> getAvailableTypes() {
		List<SelectItem> types = new ArrayList<SelectItem>();
		for (Location.TYPE type : Location.TYPE.values()) {
			types.add(new SelectItem(type, type.getLabel()));
		}
		return types;
	}

	/**
	 * Set a district property, so can get all drop-off location in this
	 * district; Use by user registration, when future user want to select a
	 * drop-off location;
	 * 
	 * @param currentDistrict
	 */
	public void setCurrentDistrict(String currentDistrict) {
		this.currentDistrict = currentDistrict;
	}

	public Set<String> getDistinctDistricts() {
		if (super.getList() != null && super.getList().size() > 0) {
			Set<String> districts = new HashSet<String>();
			// boolean exist = false;
			for (Location location : super.getList()) {
				// exist = false;
				// for (String district : districts) {
				// if (district.equalsIgnoreCase(location.getDistrict())) {
				// exist = true;
				// break;
				// }
				// }
				// if (exist == false) {
				districts.add(location.getDistrict());
				// }
			}
			return districts;
		}
		return null;
	}

	/**
	 * Get all drop-off location in the current district, this make user select
	 * drop-off location easier;
	 * 
	 * @return
	 */

	public List<Location> getCurrentDistrictLocations() {
		if (this.currentDistrict != null) {
			List<Location> locs = new LinkedList<Location>();
			for (Location location : super.getList()) {
				if (location.getDistrict().equals(this.currentDistrict)) {
					locs.add(location);
				}
			}
			return locs;
		}
		return null;
	}

	public List<SelectItem> getCurrentDistrictLocationsAsSelectItem() {
		if (this.currentDistrict != null) {
			List<SelectItem> locs = new LinkedList<SelectItem>();
			for (Location location : super.getList()) {
				if (location.getDistrict().equals(this.currentDistrict)) {
					locs.add(new SelectItem(location, location.getName() + ":"
							+ location.getAddress()));
				}
			}
			return locs;
		}
		return null;
	}

	/**
	 * This method get all available pickup days(from Sunday to Monday), so we
	 * can set pickup day for specific drop-off location;
	 * 
	 * @return
	 */
	private List<PickupSchedule> getAvailablePickupDays() {
		List<PickupSchedule> pickupSchedules = new ArrayList<PickupSchedule>();
		for (DAY_OF_WEEK day : DAY_OF_WEEK.values()) {
			PickupSchedule schedule = new PickupSchedule();
			schedule.setDayOfWeek(day);
			schedule.setIsNew(true);
			schedule.setSelected(false);
			pickupSchedules.add(schedule);
		}
		return pickupSchedules;
	}

	/**
	 * This method first get List of all available pickup days (from Sunday to
	 * Monday), those elements that exist in current location's pickup days,
	 * will point to element in current location's element; This method actually
	 * marked current location's pick-up days on all available pick-up days. so
	 * we can show it and change it;
	 * 
	 * @return
	 */
	public List<PickupSchedule> getCurrentPickupSchedules() {
		allPickupSchedules = this.getAvailablePickupDays();
		List<PickupSchedule> currentSchedules = this.getCurrent()
				.getPickupSchedules();

		for (PickupSchedule currentSchedule : currentSchedules) {
			for (int i = 0; i < allPickupSchedules.size(); i++) {
				if (allPickupSchedules.get(i).getDayOfWeek() == currentSchedule
						.getDayOfWeek()) {
					allPickupSchedules.set(i, currentSchedule);
					i = allPickupSchedules.size();
				}
			}
		}
		// CollectionUtil<PickupCalendar> util = new
		// CollectionUtil<PickupCalendar>();
		// allPickupDays = util.markList(allPickupDays, curDays);
		return allPickupSchedules;
	}

	@Override
	public Location getNewObject() {
		Location loc = new Location();
		loc.setIsNew(true);
		return loc;
	}

	public MapModel getMap() {
		String locationNote;
		for (Location loc : this.getList()) {
			if (!loc.getIsCanceled()) {
				if (loc.getLatitude() != null
						&& loc.getLatitude().isEmpty() == Boolean.FALSE
						&& loc.getLongitude() != null
						&& loc.getLongitude().isEmpty() == Boolean.FALSE) {
					locationNote = loc.getAddress() + "\n"
							+ this.getMessage("pickUpDateTime") + ":";
					for (PickupSchedule schedule : loc.getPickupSchedules()) {
						if (schedule.getIsAvailable() == Boolean.TRUE) {
							locationNote = locationNote + "\n"
									+ schedule.getDayOfWeek().getLabel() + " "
									+ schedule.getTimeRangeLabel();
						}
					}

					Marker marker = new Marker(new LatLng(
							Double.parseDouble(loc.getLatitude()),
							Double.parseDouble(loc.getLongitude())),
							locationNote);
					if ((userModel.getAuthenticatedUser() != null && userModel
							.getAuthenticatedUser().getDropOffLocation()
							.equalsId(loc))
							|| (userModel.getCurrent() != null
									&& userModel.getCurrent()
											.getDropOffLocation() != null && userModel
									.getCurrent().getDropOffLocation()
									.equalsId(loc))) {
						marker.setIcon("/resources/images/icons/system/userlocation.png");
					} else {
						marker.setIcon("/resources/images/icons/system/location.png");
					}

					marker.setData(loc.getId());
					map.addOverlay(marker);
				}
			}
		}
		return map;
	}

	public void locationChangeOnMapForCurrentUser(OverlaySelectEvent event) {
		Marker marker = (Marker) event.getOverlay();
		Long locationId = (Long) marker.getData();
		for (Location location : this.getList()) {
			if (location.getId().equals(locationId)) {
				userModel.getCurrent().setDropOffLocation(location);
				break;
			}
		}
	}

	public void locationChangeOnMapForAuthenticatedUser(OverlaySelectEvent event) {
		Marker marker = (Marker) event.getOverlay();
		Long locationId = (Long) marker.getData();
		for (Location loc : this.getList()) {
			if (loc.getId().equals(locationId)) {
				userModel.getAuthenticatedUser().setDropOffLocation(loc);
				break;
			}
		}
	}

}
